/**
 * Project of Vehicle Routing Problem with Time Windows implements 
 * some of well-known algorithms for solving VRPTW and presents new 
 * one.
 *
 * @author Michal Drobny  
 */

package io;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

import logic.car.CapacityVehicle;
import logic.car.Vehicle;
import logic.destination.Destination;
import logic.destination.SolomonInstanceDestination;
import logic.location.EuclideanLocation;
import logic.timewindow.TimeWindow;

/**
 * Represents reader for Solomon vehicle routing problem instances.
 * 
 * @author Michal Drobny
 * @date 24.11.2014
 */
public class SolomonInstanceReader {

	private final String path;
	private boolean parsed = false;
	private List<Destination> destinations;
	private List<Vehicle> vehicles;
	private String problemID;

	/**
	 * Constructor.
	 * 
	 * @param file
	 *            The file
	 */
	public SolomonInstanceReader(File file) {
		this.path = file.getPath();
	}
	
	/**
	 * Constructor.
	 * 
	 * @param path
	 *            The path
	 */
	public SolomonInstanceReader(String path) {
		this.path = path;
	}

	/**
	 * Represents a method for parsing a Solomon vehicle routing problem
	 * instance. All data values are stored in this object instance and are
	 * accessible by getter methods.
	 * 
	 * @return Whether the parsing was successful or not
	 */
	public boolean parse() {
		
		CSVReader reader;
		try {
			reader = new CSVReader(path);
		} catch (FileNotFoundException e) {
			return false;
		}

		if (!reader.hasString())
			return false;

		problemID = reader.nextString();

		reader.getLine();
		reader.getLine();
		reader.getLine();
		reader.getLine();

		if (!reader.hasInt())
			return false;

		int vehicleCount = reader.nextInt();

		if (!reader.hasInt())
			return false;

		int vehicleCapacity = reader.nextInt();

		reader.getLine();
		reader.getLine();
		reader.getLine();
		reader.getLine();
		
		destinations = new ArrayList<Destination>();
		parsed = parseDestinations(reader);
		
		vehicles = new ArrayList<Vehicle>();
		// count of vehicles is modified to count of destinations!
		for (int i = 0; i < vehicleCount; i++) {
			vehicles.add(new CapacityVehicle("vehicle " + i, vehicleCapacity));
		}
		
		return parsed;
	}

	/**
	 * Parses destinations from the Solomon vehicle routing problem instance.
	 * 
	 * @param reader
	 *            CSV reader
	 * @return Whether the destinations was successfully parsed
	 */
	private boolean parseDestinations(CSVReader reader) {
		List<Destination> result = new ArrayList<Destination>();
		while (parseDestination(reader, result)) {}
		
		if (result.isEmpty())
			return false;
		else {
			this.destinations = result;
			return true;
		}
	}

	/**
	 * Parses destination from the Solomon vehicle routing problem instance.
	 * 
	 * @param reader
	 *            CSV reader
	 * @param destinations
	 *            The array of destinations
	 * @param destinationsCount
	 *            The count of destinations
	 * @return
	 */
	private boolean parseDestination(CSVReader reader,
			List<Destination> destinations) {
		int destId = 0, xAxis = 0, yAxis = 0, demand = 0;
		long startTime = 0l, endTime = 0l, timeDelay = 0l;
		
		if (!reader.hasInt())
			return false;
		destId = reader.nextInt();
		
		if (!reader.hasInt())
			return false;
		xAxis = reader.nextInt();
		
		if (!reader.hasInt())
			return false;
		yAxis = reader.nextInt();
		
		if (!reader.hasInt())
			return false;
		demand = reader.nextInt();
		
		if (!reader.hasLong())
			return false;
		startTime = reader.nextLong();
		
		if (!reader.hasLong())
			return false;
		endTime = reader.nextLong();
		
		if (!reader.hasLong())
			return false;
		timeDelay = reader.nextLong();
		
		SolomonInstanceDestination result = 
				new SolomonInstanceDestination(
						String.valueOf(destId),
						new TimeWindow<Long>(startTime, endTime),
						demand,
						new EuclideanLocation(xAxis, yAxis),
						timeDelay);
		destinations.add(result);
		reader.getLine();
		return true;
	}

	/**
	 * @return the parsed
	 */
	public boolean isParsed() {
		return parsed;
	}

	/**
	 * @return the destinations
	 */
	public List<Destination> getDestinations() {
		if (!parsed)
			return null;

		return destinations;
	}

	/**
	 * @return the vehicles
	 */
	public List<Vehicle> getVehicles() {
		if (!parsed)
			return null;

		return vehicles;
	}

	/**
	 * @return the problemID
	 */
	public String getProblemID() {
		if (!parsed)
			return null;

		return problemID;
	}
}